package com.bestv.search.management.command;

import com.bestv.search.common.cache.SystemCache;
import com.bestv.search.common.dataSource.DataSourceKey;
import com.bestv.search.common.dataSource.DataSourceKeyUtil;
import com.bestv.search.common.model.Info;
import com.bestv.search.common.model.InfoHeader;
import com.bestv.search.common.model.SysUser;
import com.bestv.search.common.model.Tag;
import com.bestv.search.common.service.InfoHeaderManager;
import com.bestv.search.common.service.InfoManager;
import com.bestv.search.common.util.CommonUtil;
import com.bestv.search.common.util.Excel;
import com.bestv.search.common.util.ExcelSheet;
import com.bestv.search.common.util.StringConst;
import com.bestv.search.management.xfire.ISearchWS;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.codehaus.xfire.client.XFireProxyFactory;
import org.codehaus.xfire.service.Service;
import org.codehaus.xfire.service.binding.ObjectServiceFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.util.StringUtils;

import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.text.SimpleDateFormat;
import java.util.*;

public class InfoCommand {
    protected final Log log = LogFactory.getLog(getClass());
    private InfoManager infoManager;
    private InfoHeaderManager infoHeaderManager;
    private SystemCache systemCache;

    public InfoManager getInfoManager() {
        return infoManager;
    }

    public void setInfoManager(InfoManager infoManager) {
        this.infoManager = infoManager;
    }

    public String find(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) throws JSONException {
        String[] start = map.get("start");
        String[] limit = map.get("limit");
        String[] infoTypes = map.get("infoType");
        String infoType = "Info";
        if (infoTypes != null && !"".equals(infoTypes[0]))
            infoType = infoTypes[0];

        int stat = 0, lmt = 20;
        if ("".equals(start[0]))
            stat = -1;
        else
            stat = Integer.parseInt(start[0]);
        if ("".equals(limit))
            lmt = -1;
        else
            lmt = Integer.parseInt(limit[0]);

        int count = infoManager.getCountByType(dsKey, infoType);
        List<Info> infos = infoManager.getInfosByType(dsKey, stat, lmt, infoType);
        if (infos == null || infos.size() == 0)
            return "{'totalCount':0,'infos':[]}";
        JSONArray array = new JSONArray();
        for (Info info : infos)
            array.put(infoToJSONObject(info));
        return "{'totalCount':" + count + ",'infos':" + array.toString() + "}";
    }

    public String findInfoFromEngine(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) {

        // Gets infos from engine.
        ISearchWS service;
        Service serviceModel = new ObjectServiceFactory().create(ISearchWS.class);
        String url = systemCache.getWebServiceEngineUrls().get(dsKey.toString());
        String[] soapUrls = StringUtils.tokenizeToStringArray(url, SystemCache.WEB_SERVICE_EURL_DELIMITERS);

        if (soapUrls == null || soapUrls.length == 0) {
            log.error("Gets info failed, no web service interface found from site " + dsKey.toString());
            return "{'totalCount':0,'results':[error]}";
        }

        String infos = null;
        String avatarRoot = null;
        if (soapUrls.length > 0) {
            // Gets service form engine1
            String soapUrl = soapUrls[0];
            log.info("Search info from " + soapUrl);
            avatarRoot = soapUrl.replace("/SearchService.ws", "/avatar/");

            try {
                service = (ISearchWS) new XFireProxyFactory().create(serviceModel, soapUrl);
                String docStr = buildQueryDoc(map);
                String[] searchCmd = map.get("searchCmd");
                if (docStr != null) {
                    infos = service.searchByDoc(docStr.getBytes(),
                            searchCmd != null && !searchCmd[0].equals("") ? searchCmd[0] : "searchCategory");
                }
            } catch (MalformedURLException e) {
                log.error("Gets info failed from " + soapUrl);
                log.error(e);
                e.printStackTrace();
                return "{'totalCount':0,'results':[error]}";
            }
        }

        String jsonObject = null;
        if (infos == null) {
            jsonObject = "{'totalCount': 0 }";
        } else {
            try {
                jsonObject = convertXmlStrToJson(infos, dsKey.toString(), avatarRoot);
            } catch (JSONException e) {
                log.error("Convert to JSON Object failed");
                log.error(e);
                e.printStackTrace();
                jsonObject = "{'totalCount':0,'results':[error]}";
            }
        }

        return jsonObject;
    }

    public String findPersonDetailFromEngine(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) {

        // Gets infos from engine.
        ISearchWS service;
        Service serviceModel = new ObjectServiceFactory().create(ISearchWS.class);
        String url = systemCache.getWebServiceEngineUrls().get(dsKey.toString());
        String[] soapUrls = StringUtils.tokenizeToStringArray(url, SystemCache.WEB_SERVICE_EURL_DELIMITERS);

        if (soapUrls == null || soapUrls.length == 0) {
            log.error("Gets persond details failed, no web service interface found from site " + dsKey.toString());
            return StringConst.EMPTY;
        }

        String person = null;
        String avatarRoot = null;
        if (soapUrls.length > 0) {
            // Gets service form engine1
            String soapUrl = soapUrls[0];
            log.info("Search info from " + soapUrl);
            avatarRoot = soapUrl.replace("/SearchService.ws", "/avatar/");

            try {
                service = (ISearchWS) new XFireProxyFactory().create(serviceModel, soapUrl);

                String[] personId = map.get("personId");
                String[] productFlag = map.get("productFlag");

                person = service.getPersonByDoc(personId[0], avatarRoot,
                        productFlag == null ? 0 : Integer.valueOf(productFlag[0]));
            } catch (MalformedURLException e) {
                log.error("Gets info failed from " + soapUrl);
                log.error(e);
                e.printStackTrace();
                return StringConst.EMPTY;
            }
        }

        String jsonObject = null;
        if (person == null) {
            jsonObject = StringConst.EMPTY;
        } else {
            try {
                jsonObject = convertPersonToJson(person);
            } catch (JSONException e) {
                log.error("Convert to JSON Object failed");
                log.error(e);
                e.printStackTrace();
                jsonObject = StringConst.EMPTY;
            }
        }

        return jsonObject;
    }

    public String offLineVod(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) {
        String[] code = map.get("code");

        if (code != null) {
            String[] codeArray = code[0].split(",");
            if (infoManager.saveOffLineInfoByCode(dsKey, Arrays.asList(codeArray))) {
                log.info("Off line vods successfully [User: " + user.getUsername() + ","
                        + Arrays.asList(codeArray).toString() + "]");
                return "success";
            }
        }
        return "failed";
    }

    public String updateInfoUpFlag(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) {
        String[] paras = map.get("jsonPara");
        if (paras == null || paras.length == 0) {
            return "failed";
        } else {
            String paraJSON = paras[0];
            List<Info> list = CommonUtil.convertJSONStrTOList(paraJSON, new Info());
            for (Info parameter : list) {
                // Handle InfoHeader
                if (parameter.getInfoFlag() == 2) {
                    InfoHeader infoHeader = infoHeaderManager.get(dsKey, parameter.getId());
                    infoHeader.setUp_flag(parameter.getUp_flag());
                    infoHeader.setUpdate_time_for_index(new Date());
                    infoHeaderManager.saveOrUpdate(dsKey, infoHeader);
                } else {
                    // Handle info
                    infoManager.saveInfoUpFlag(dsKey, parameter);
                }
            }
        }

        return "success";
    }

    public String getNetInfoIdByMediaCode(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) {
        String[] code = map.get("code");
        String id = null;
        if (code != null && code.length > 0) {
            id = infoManager.getNetInfoIdByMediaCode(dsKey, code[0]);
        }
        return id == null ? "" : id;
    }

    public String getComparedInfo(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) throws JSONException {
        String[] code = map.get("code");
        String[] p_type = map.get("type");
        if (code == null || code.length == 0) {
            log.error("Media code is necessary, please provide.");
            return "{'result':''}";
        }

        if (p_type == null || p_type.length == 0) {
            log.error("p_type is necessary, please provide.");
            return "{'result':''}";
        }

        // Gets Data from DB
        List<Object[]> list = infoManager.getComparedInfo(dsKey, code[0], p_type[0]);

        // Gets json String
        JSONArray array = new JSONArray();
        for (Object[] obj : list) {
            JSONObject jo = new JSONObject();
            jo.put("field", obj[0] == null ? "" : obj[0].toString());
            jo.put("localValue", obj[1] == null ? "" : obj[1].toString());
            jo.put("netValue", obj[2] == null ? "" : obj[2].toString());
            array.put(jo);
        }

        return "{'result':" + array.toString() + "}";
    }

    public String delete(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) {
        String[] id = map.get("id");

        infoManager.delete(dsKey, new Long(id[0]));
        return "{'result':'success','message':''}";
    }

    private JSONObject infoToJSONObject(Info info) throws JSONException {
        JSONObject jo = new JSONObject();
        jo.put("id", String.valueOf(info.getId()));
        jo.put("code", info.getCode());
        jo.put("name", info.getName());
        if (info.getSubType() != null)
            jo.put("subType", info.getSubType().getName());
        Set<Tag> tagSet = info.getTags();
        if (tagSet != null && tagSet.size() > 0) {
            StringBuffer tf = new StringBuffer();
            for (Tag tag : tagSet)
                tf.append(tag.getTag()).append(" ");
            jo.put("tags", tf.toString());
        } else
            jo.put("tags", "");
        jo.put("status", info.getStatus());
        return jo;
    }

    private String buildQueryDoc(Map<String, String[]> map) {
        // TODO temp disable offline for '节目单'.
        String[] defaultInfoTypes = {"电影  电视剧  少儿 娱乐 音乐 凤凰 新闻 法治 体育 时尚生活 财经 纪实 军事 其他 预告片 影讯"};

        String[] infoTypes = map.get("infoType");
        String[] keyword = map.get("keyword");
        String[] start = map.get("start");
        String[] limit = map.get("limit");
        String[] searchCmd = map.get("searchCmd");
        String[] nationality = map.get("nationality");
        String[] loadAllUpInfo = map.get("loadAllUpInfo");

        StringBuilder xml = new StringBuilder();
        // Xml header.
        xml.append("<?xml version=\"1.0\" encoding=\"" + StringConst.UTF_8 + "\" ?>");

        // Request start
        xml.append("<request>");

        // CMD node
        if (searchCmd != null && !searchCmd[0].equals("")) {
            xml.append("<cmd>" + searchCmd[0] + "</cmd>");
        } else {
            // default cmd
            xml.append("<cmd>searchCategory</cmd>");
        }

        // Start Node
        int startRow = 0;
        if (start != null && !start[0].equals("")) {
            startRow = Integer.valueOf(start[0]);
        }
        xml.append("<start>" + startRow + "</start>");

        // Limit Node
        int limitRow = 30;
        if (limit != null && !limit[0].equals("")) {
            limitRow = Integer.valueOf(limit[0]);
        }
        xml.append("<limit>" + limitRow + "</limit>");

        if (loadAllUpInfo != null && !loadAllUpInfo[0].equals("") && Boolean.parseBoolean(loadAllUpInfo[0])) {
            xml.append("<filter>");
            xml.append("<field>" + StringConst.UP_FLAG + "</field>");
            xml.append("<value>1</value>");
            xml.append("</filter>");
        } else {
            // Keyword node
            if (keyword == null || keyword[0].equals("")) {
                log.error("Search keyword is null or empty, please type in");
                return null;
            }
            xml.append("<keywords>" + keyword[0] + "</keywords>");
        }
        // TODO temp disable offline for '节目单'.
        if (infoTypes == null || (infoTypes.length == 1 && infoTypes[0].equals("节目单"))) {
            infoTypes = defaultInfoTypes;
        }

        // Filter node
        if (infoTypes != null) {
            xml.append("<filter>");
            xml.append("<field>bizType</field>");

            StringBuilder sb = new StringBuilder();
            for (String type : infoTypes[0].split(" ")) {
                // TODO temp disable offline for '节目单'.
                if (type.equals("节目单"))
                    continue;
                sb.append(type + " ");
            }
            xml.append("<value>" + sb.toString() + "</value>");
            xml.append("</filter>");
        }

        if (nationality != null && nationality.length != 0 && !nationality[0].trim().equals(StringConst.EMPTY)
                && !nationality[0].startsWith("全部")) {
            xml.append("<filter>");
            xml.append("<field>nationality</field>");
            xml.append("<value>" + nationality[0] + "</value>");
            xml.append("</filter>");
        }

        // Request node end.
        xml.append("</request>");

        return xml.toString();
    }

    private String convertXmlStrToJson(String infos, String siteCode, String avatarRoot) throws JSONException {
        SAXReader reader = new SAXReader();
        Document doc = null;
        try {
            try {
                doc = reader.read(new InputStreamReader(new ByteArrayInputStream(infos.getBytes()), StringConst.UTF_8));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        } catch (DocumentException e) {
            log.error("Error!The Request Parameter cannot parse to XML");
            log.error(e);
            return "{'totalCount':0,'results':[error]}";
        }

        JSONArray array = new JSONArray();
        String totalCount = doc.selectSingleNode("/result/count").getText();

        // Gets infos by code
        @SuppressWarnings("unchecked")
        List<Node> codeNodes = doc.selectNodes("/result/records/record/code");
        List<String> infoCodes = new ArrayList<String>();
        // Gets info code list.
        for (Node code : codeNodes) {
            infoCodes.add(code.getText());
        }

        // Gets info list
        DataSourceKey key = DataSourceKeyUtil.convert(siteCode);
        List<Info> infoList = infoManager.getInfoByCode(key, infoCodes);

        // Convert result to JSONArray.
        @SuppressWarnings("unchecked")
        List<Node> records = doc.selectNodes("/result/records/record");
        for (Node record : records) {
            JSONObject obj = new JSONObject();
            obj.put("name", record.selectSingleNode("name").getText());
            obj.put("bizType", record.selectSingleNode("bizType").getText());

            String code = record.selectSingleNode("code").getText();
            obj.put("code", code);

            String updateTimeForIndex = "";
            // Gets updateTimeForIndex from info
            if (!"节目单".equals(record.selectSingleNode("bizType").getText())) {
                for (Info info : infoList) {
                    if (code != null && code.equals(info.getCode())) {
                        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        updateTimeForIndex = dateFormat.format(info.getUpdateTimeForIndex());
                        break;
                    }
                }
            } else {
                // Gets updateTimeForIndex from startTime
                updateTimeForIndex = record.selectSingleNode("startTime").getText();
            }
            obj.put("updateTimeForIndex", updateTimeForIndex);

            // Gets info flag
            Node infoFlag = record.selectSingleNode(StringConst.INFO_FLAG);
            if (infoFlag == null) {
                obj.put(StringConst.INFO_FLAG, String.valueOf(0));
            } else {
                obj.put(StringConst.INFO_FLAG, infoFlag.getText());
            }

            // Gets up flag
            Node upFlag = record.selectSingleNode(StringConst.UP_FLAG);
            if (upFlag != null) {
                obj.put(StringConst.UP_FLAG, upFlag.getText());
            }

            // Gets info id
            Node infoID = record.selectSingleNode(StringConst.ID);
            if (infoID != null) {
                obj.put(StringConst.ID, infoID.getText());
            }
            obj.put("index", record.selectSingleNode("index").getText());

            Node avatar = record.selectSingleNode("avatar");
            if (avatar != null) {
                obj.put("avatar", avatarRoot + avatar.getText());
            }

            array.put(obj);
        }

        return "{'totalCount':" + totalCount + ",'results':" + array.toString() + "}";
    }

    private String convertPersonToJson(String personXml) throws JSONException {
        SAXReader reader = new SAXReader();
        Document doc = null;
        try {
            try {
                doc = reader.read(new InputStreamReader(new ByteArrayInputStream(personXml.getBytes()),
                        StringConst.UTF_8));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        } catch (DocumentException e) {
            log.error("Error!The Request Parameter cannot parse to XML");
            log.error(e);
            return "{'totalCount':0,'results':[error]}";
        }

        JSONObject personJson = new JSONObject();
        Node name = doc.selectSingleNode("/record/name");

        personJson.put("name", name == null ? StringConst.EMPTY : name.getText());

        Node avatar = doc.selectSingleNode("/record/avatar");
        personJson.put("avatar", avatar == null ? StringConst.EMPTY : avatar.getText());

        Node gender = doc.selectSingleNode("/record/gender");
        String sex = StringConst.EMPTY;
        if (gender == null) {
            sex = StringConst.EMPTY;
        } else if ("m".equalsIgnoreCase(gender.getText())) {
            sex = "男";
        } else if ("f".equalsIgnoreCase(gender.getText())) {
            sex = "女";
        } else if ("g".equalsIgnoreCase(gender.getText())) {
            sex = "组合";
        }
        personJson.put("gender", sex);

        Node nationality = doc.selectSingleNode("/record/nationality");
        personJson.put("nationality", nationality == null ? StringConst.EMPTY : nationality.getText());

        Node bloodtype = doc.selectSingleNode("/record/bloodtype");
        personJson.put("bloodtype", bloodtype == null ? StringConst.EMPTY : bloodtype.getText());

        Node constellation = doc.selectSingleNode("/record/constellation");
        personJson.put("constellation", constellation == null ? StringConst.EMPTY : constellation.getText());

        Node birthday = doc.selectSingleNode("/record/birthday");
        personJson.put("birthday", birthday == null ? StringConst.EMPTY : birthday.getText());

        Node height = doc.selectSingleNode("/record/height");
        personJson.put("height", height == null ? StringConst.EMPTY : height.getText());

        Node alias = doc.selectSingleNode("/record/alias");
        personJson.put("alias", alias == null ? StringConst.EMPTY : alias.getText());

        Node homeplace = doc.selectSingleNode("/record/homeplace");
        personJson.put("homeplace", homeplace == null ? StringConst.EMPTY : homeplace.getText());

        Node description = doc.selectSingleNode("/record/description");
        personJson.put("description", description == null ? StringConst.EMPTY : description.getText());

        Node honor = doc.selectSingleNode("/record/honor");
        personJson.put("honor", honor == null ? StringConst.EMPTY : honor.getText());

        JSONArray productsArray = new JSONArray();
        @SuppressWarnings("unchecked")
        List<Node> products = doc.selectNodes("/record/products/item");
        if (products != null && products.size() > 0) {
            for (Node node : products) {
                JSONObject productJson = new JSONObject();
                productJson.put("name", node.selectSingleNode("name").getText());
                productJson.put("year", node.selectSingleNode("year").getText());
                productJson.put("category", node.selectSingleNode("category").getText());
                productJson.put("description", node.selectSingleNode("description").getText());

                @SuppressWarnings("unchecked")
                List<Node> onlineInfos = node.selectNodes("onlineInfos/info");
                JSONArray onlinesArray = new JSONArray();
                if (onlineInfos != null && onlineInfos.size() > 0) {
                    for (Node onlineInfo : onlineInfos) {
                        JSONObject onlineInfoJson = new JSONObject();
                        onlineInfoJson.put("name", onlineInfo.selectSingleNode("name").getText());
                        onlineInfoJson.put("code", onlineInfo.selectSingleNode("code").getText());
                        onlinesArray.put(onlineInfoJson);
                    }
                }
                productJson.put("onlineInfos", onlinesArray.toString());
                productsArray.put(productJson);
            }
        }
        personJson.put("products", productsArray.toString());

        JSONArray results = new JSONArray();
        results.put(personJson);

        return results.toString();
    }

    public String geTopNInfosToJSON(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) {
        // Gets type
        String[] types = map.get("type");
        if (types == null || "".equals(types[0])) {
            log.error("Gets topN infos failed, missing parameter type.");
            return "{'totalCount':0,'results':[error]}";
        }

        // Gets increaseFlag
        String[] increases = map.get("increase");
        boolean increaseFlag = false;
        if (increases != null && !"".equals(increases[0])) {
            try {
                increaseFlag = Boolean.parseBoolean(increases[0]);
            } catch (Exception e) {
                log.warn("Parse increase node to boolean error!");
                increaseFlag = false;
            }
        }

        // Gets merge type
        String[] mergeTypes = map.get("mergeType");
        int mergeType = 1;
        if (mergeTypes != null && !"".equals(mergeTypes[0])) {
            try {
                mergeType = Integer.parseInt(mergeTypes[0]);
            } catch (Exception e) {
                log.warn("Parse increase node to boolean error!");
                increaseFlag = false;
            }
        }

        // Gets topN
        String[] limits = map.get("topN");
        int topN = 10;
        if (limits != null && !"".equals(limits[0])) {
            try {
                topN = Integer.parseInt(limits[0]);
            } catch (Exception e) {
                log.warn("Parse increase node to boolean error!");
                topN = 10;
            }
        }

        // Gets Categorys
        String[] categorys = map.get("category");
        if (categorys != null && "全部".equals(categorys[0])) {
            // Set categorys =null that means don't have category limit, will
            // get total topN leader board.
            categorys = null;
        }

        // Gets topN infos from engine.
        ISearchWS service;
        Service serviceModel = new ObjectServiceFactory().create(ISearchWS.class);
        String url = systemCache.getWebServiceEngineUrls().get(dsKey.toString());
        String[] soapUrls = StringUtils.tokenizeToStringArray(url, SystemCache.WEB_SERVICE_EURL_DELIMITERS);
        if (soapUrls == null) {
            log.error("Gets topN infos failed, no web service interface found from site " + dsKey.toString());
            return "{'results':[error]}";
        }

        // Gets topN infos from engine service
        if (soapUrls.length > 0) {
            // Gets service form engine1
            String soapUrl = soapUrls[0];
            log.info("Gets topN infos from " + soapUrl);
            try {
                service = (ISearchWS) new XFireProxyFactory().create(serviceModel, soapUrl);
                return "{'results':" + service.getTopNINfosToJSON(types[0], increaseFlag, mergeType, topN, categorys)
                        + "}";
            } catch (Exception e) {
                log.error("Gets info failed from " + soapUrl);
                log.error(e);
                e.printStackTrace();
                return "{'results':[error]}";
            }
        } else {
            return "{'results':[error]}";
        }
    }

    public HSSFWorkbook createExcel(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) {
        final String rowNoColName = "排名";
        final String vodNameColName = "节目名称";
        final String codeColName = "code";
        final String categoryColName = "节目分类";
        final String isHeaderColName = "剧头";
        final String countColName = "播放数";
        final String increaseColName = "上升名次";

        // Gets topN
        String[] topNs = map.get("topN");
        int topN = 10;
        if (topNs != null && !"".equals(topNs[0])) {
            try {
                topN = Integer.parseInt(topNs[0]);
            } catch (Exception e) {
                log.warn("Parse increase node to boolean error!");
                topN = 10;
            }
        }
        // Gets increaseFlag
        String[] increases = map.get("increase");
        boolean increaseFlag = false;
        if (increases != null && !"".equals(increases[0])) {
            try {
                increaseFlag = Boolean.parseBoolean(increases[0]);
            } catch (Exception e) {
                log.warn("Parse increase node to boolean error!");
                increaseFlag = false;
            }
        }

        List<String> header = new ArrayList<String>();
        header.add(rowNoColName);
        header.add(vodNameColName);
        header.add(codeColName);
        header.add(categoryColName);
        header.add(isHeaderColName);
        header.add(countColName);
        if (increaseFlag) {
            header.add(increaseColName);
        }

        List<ExcelSheet> sheets = new ArrayList<ExcelSheet>();
        // gets daily sheet
        List<String[]> list = getTopNInfos(StringConst.DAILY, increaseFlag, 1, topN, null, dsKey);
        if (list == null) {
            return null;
        }
        sheets.add(formatDataForExport(list, header, "日排行", topN));

        // gets week sheet
        list = getTopNInfos(StringConst.WEEKLY, increaseFlag, 1, topN, null, dsKey);
        if (list == null) {
            return null;
        }
        sheets.add(formatDataForExport(list, header, "周排行", topN));

        // gets month sheet
        list = getTopNInfos(StringConst.MONTHLY, increaseFlag, 1, topN, null, dsKey);
        if (list == null) {
            return null;
        }
        sheets.add(formatDataForExport(list, header, "月排行", topN));

        // gets quarter sheet
        list = getTopNInfos(StringConst.QUARTER, increaseFlag, 1, topN, null, dsKey);
        if (list == null) {
            return null;
        }
        sheets.add(formatDataForExport(list, header, "季排行", topN));

        if (!increaseFlag) {
            // gets total sheet
            list = getTopNInfos("total", increaseFlag, 1, topN, null, dsKey);
            if (list == null) {
                return null;
            }
            sheets.add(formatDataForExport(list, header, "总排行", topN));
        }

        // create excel file.
        Excel excel = new Excel();
        HSSFWorkbook book = excel.create(sheets);

        return book;
    }

    private List<String[]> getTopNInfos(String type, boolean increaseFlag, int mergeType, int topN, String[] categorys,
                                        DataSourceKey dsKey) {
        List<String[]> results = new ArrayList<String[]>();

        // Gets topN infos from engine service
        ISearchWS service;
        Service serviceModel = new ObjectServiceFactory().create(ISearchWS.class);
        String url = systemCache.getWebServiceEngineUrls().get(dsKey.toString());
        String[] soapUrls = StringUtils.tokenizeToStringArray(url, SystemCache.WEB_SERVICE_EURL_DELIMITERS);
        if (soapUrls == null) {
            log.error("Gets topN infos failed, no web service interface found from site " + dsKey.toString());
        } else {
            if (soapUrls.length > 0) {
                // Gets service form engine1
                String soapUrl = soapUrls[0];
                log.info("Gets topN infos from " + soapUrl);
                try {
                    service = (ISearchWS) new XFireProxyFactory().create(serviceModel, soapUrl);
                    List<List<String>> responseList = service
                            .topnToList(type, increaseFlag, mergeType, topN, categorys);

                    if (responseList != null && responseList.size() > 0) {
                        int rowSize = 6;
                        if (increaseFlag) {
                            rowSize = 7;
                        }
                        for (List<String> list : responseList) {
                            String[] row = new String[rowSize];
                            row[0] = list.get(0);
                            row[1] = list.get(1);
                            row[2] = list.get(2);
                            row[3] = list.get(3);
                            row[4] = list.get(4);
                            row[5] = list.get(5);
                            if (increaseFlag) {
                                row[6] = list.get(6);
                            }
                            results.add(row);
                        }
                    }
                } catch (Exception e) {
                    log.error("Gets info failed from " + soapUrl);
                    log.error(e);
                    e.printStackTrace();
                }
            }
        }

        return results;
    }

    private ExcelSheet formatDataForExport(List<String[]> data, List<String> header, String sheetName, int topN) {
        ExcelSheet sheet = new ExcelSheet();
        sheet.setSheetName(sheetName);
        sheet.setDataHeader(header);
        sheet.setData(data);
        return sheet;
    }

    public String getInfosLikeName(SysUser user, Map<String, String[]> map, DataSourceKey dsKey) {
        String[] names = map.get("name");
        String[] starts = map.get("start");
        String[] limits = map.get("limit");

        if (names == null || names.length == 0) {
            log.error("Gets info failed, please provide info name");
            return "{'totalCount':0,'results':[ERROR]}";
        } else {
            int startInt = 0;
            if (starts != null && starts.length > 0) {
                try {
                    startInt = Integer.valueOf(starts[0]);
                } catch (Exception e) {
                    log.warn("Invalid parameter start " + starts[0]);
                    startInt = 0;
                }
            }

            int limitInt = 20;
            if (limits != null && limits.length > 0) {
                try {
                    limitInt = Integer.valueOf(limits[0]);
                } catch (Exception e) {
                    log.warn("Invalid parameter start " + limits[0]);
                    limitInt = 20;
                }
            }

            List<Info> infos = infoManager.getInfoLikeName(dsKey, names[0], startInt, limitInt);
            int total = infoManager.getInfoCountLikeName(dsKey, names[0]);

            JSONArray array = new JSONArray();
            for (Info info : infos) {
                JSONObject json = new JSONObject();
                try {
                    json.put("id", String.valueOf(info.getId()));
                    json.put("name", info.getName());
                    json.put("code", info.getCode());
                    json.put("p_type", info.getP_type());
                    json.put("hd", info.getHd());
                    json.put("description", info.getDescription());
                    json.put("contentFlag", info.getContent_flag());

                    String version = info.getContent_version();
                    if ((version == null || version.equals(StringConst.EMPTY)) && info.getName() != null) {
                        if (info.getName().equals(StringConst.ORIGINAL_SOUND_CHINESE)) {
                            version = StringConst.ORIGINAL_SOUND_CHINESE;
                        } else if (info.getName().equals(StringConst.MANDARIN_SOUND_CHINESE)) {
                            version = StringConst.MANDARIN_SOUND_CHINESE;
                        } else if (info.getName().equals(StringConst.CANTONESE_CHINESE)) {
                            version = StringConst.CANTONESE_CHINESE;
                        } else {
                            version = StringConst.ORIGINAL_SOUND_CHINESE;
                        }
                    }

                    json.put("contentVersion", version);
                    array.put(json);
                } catch (JSONException e) {
                    log.error("Convert to Json object failed.");
                    e.printStackTrace();
                }
            }
            return "{'totalCount':" + total + ",'results':" + array.toString() + "}";
        }
    }

    public SystemCache getSystemCache() {
        return systemCache;
    }

    public void setSystemCache(SystemCache systemCache) {
        this.systemCache = systemCache;
    }

    public InfoHeaderManager getInfoHeaderManager() {
        return infoHeaderManager;
    }

    public void setInfoHeaderManager(InfoHeaderManager infoHeaderManager) {
        this.infoHeaderManager = infoHeaderManager;
    }
}
